package com.fu.utils;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;

/**
 * 实现参数校验的工具类
 * @author Little Ant
 * @date 2017年10月30日下午5:51:02
 */
public class CheckUtils {

	private static final int DEFAULT_VALID_TIME = 30;
	private static final String UTF_8 = "UTF-8";

	private CheckUtils(){}

	public static String requestCheck(HttpServletRequest request) throws UnsupportedEncodingException {
		String sign = request.getParameter("sign");
		String timestamp = request.getParameter("timestamp");
		String token = request.getParameter("token");
		// 无效的请求参数
		if (sign == null || "".equals(sign) || timestamp == null || "".equals(timestamp) || token == null
				|| "".equals(token) ) {
			return Constants.INVALID_REQUEST_PARAMATERS;
		}
		// todo 可以做成过滤链？
		// 请求超时
		int minutes = DateTimeUtils.getIntervalMinutes(timestamp, Long.toString(System.currentTimeMillis()));
		if (minutes > DEFAULT_VALID_TIME || minutes < 0) {
			return Constants.REQUEST_OUT_OF_TIME;
		}

		String createSign = createSign(parameterMap(request), true);
		// 无效的参数签名
		if (!sign.equals(createSign)) {
			return Constants.INVALID_SIGN;
		}
		return Constants.SUCCESS_MESSAGE;
	}

	/**
	 * 将除了 sign 的请求参数和其值作为键值对返回
	 * @param request 原始请求参数
	 * @return Map<String,String>
	 */
	private static Map<String, String> parameterMap(HttpServletRequest request) {
		Map<String, String> parameterMap = new HashMap<>();
		Enumeration<String> names = request.getParameterNames();
		while (names.hasMoreElements()) {
			String name = names.nextElement();
			String value = request.getParameter(name);
			if (!"sign".equals(name)) {
				parameterMap.put(name, value);
			}
		}
		return parameterMap;
	}

	/**
	 * 根据所有请求参数生成签名sign
	 * @param map
	 * @param encode 是否编码
	 * @return String
	 * @throw UnsupportedEncodingException
	 */
	private static String createSign(Map<String, String> map, boolean encode) throws UnsupportedEncodingException {
		Set<String> keySet = map.keySet();
		Object[] keys = keySet.toArray();
		// 根据字母排序
		Arrays.sort(keys);

		StringBuilder temp = new StringBuilder();
		boolean first = true;
		for (Object key : keys) {
			if (first) {
				first = false;
			} else {
				temp.append("&");
			}
			temp.append(key).append("=");
			String value = map.get(key) == null ? "" :  map.get(key);
			value = encode ? URLEncoder.encode(value, UTF_8) : value;
			temp.append(value);
		}
		return Md5Util.md5Encode(temp.toString(), UTF_8).toUpperCase();
	}
}
